// 编译类
// 递归遍历dom树
// 判断节点类型，如果是文本，则判断是否是插值绑定
// 如果是元素，则遍历其属性是否是指令或事件，然后递归子元素

class Compile {
  constructor(el, vm) {
    this.$vm = vm
    this.$el = document.querySelector(el)

    if (this.$el) {
      this.compile(this.$el)
    }
  }

  compile (el) {
    // 遍历el树
    const childNodes = el.childNodes
    console.log('childNodes', childNodes)
    Array.from(childNodes).forEach(node => {
      if (this.isElement(node)) {
        console.log('编译元素', node.nodeName)
        this.compileElement(node)
      } else if (this.isInter(node)) {
        console.log('编译一下插值绑定', node.textContent)
        this.compileText(node)
      }

      // 递归子节点
      if (node.childNodes && node.childNodes.length > 0) {
        this.compile(node)
      }
    }) 
  }

  isElement (node) {
    return node.nodeType === 1
  }

  isInter (node) {
    // 首先是文本，其次内容是{{xxx}}
    return node.nodeType === 3 && /\{\{(.*)\}\}/.test(node.textContent)
  }

  compileText (node) {
    // node.textContent = this.$vm[RegExp.$1]
    this.update(node, RegExp.$1, 'text') 
  }

  compileElement (node) {
    // 节点是元素，遍历其属性列表
    const nodeAttrs = node.attributes
    Array.from(nodeAttrs).forEach(attr => {
      // 规定： 指令以k-xx开头
      const attrName = attr.name //k-xx
      console.log('attrName', attrName)
      const exp = attr.value //oo
      if (this.isDirective(attrName)) {
        const dir = attrName.substring(2)
        // 执行指令
        this[dir] && this[dir](node, exp)
        // console.log('attrName', attrName)
        if (attrName === 'k-model') {
          node.addEventListener('input', (e) => {
            console.log('e', e)
            this.$vm[exp] = node.value
          })   
        }
      } else if (this.isEvent(attrName)) {
        const dir = attrName.substring(1) //@click=""
        let eventName = node.getAttribute(attrName)
        // console.log('11111',  node.getAttribute(attrName))
        let eventValue = ''
        if (/([a-z]*)\((.*)\)$/.test(eventName)) {
          eventName = RegExp.$1
          eventValue = RegExp.$2
        }
        console.warn('eventName', eventName, eventValue)
        node.addEventListener(dir, this.$vm.$methods[eventName].bind(this.$vm, eventValue))   
      }
    })
  }

  isDirective(attr) {
    return attr.indexOf('k-') === 0
  }

  isEvent (attr) {
    return attr.indexOf('@') === 0
  }

  // 公共的更细函数
  update(node, exp, dir) {
    // 指令对应更新函数xxUpdate
    const fn = this[dir + 'Updater']
    fn && fn(node, this.$vm[exp])

    // 更新处理 封装一个更新函数，可以更新对应dom元素
    new Watcher(this.$vm, exp, (val) =>{
      fn && fn(node, val)
    })
  }

  textUpdater (node, value) {
    node.textContent = value
  }

  htmlUpdater (node, value) {
    node.innerHTML = value
  }

  modelUpdater (node, value) {
    console.warn('node', node, value)
    node.setAttribute('value', value)
  }

  // k-model
  model(node, exp) {
    this.update(node, exp, 'model')
  }

  // k-text
  text(node, exp) {
    // node.textContent = this.$vm[exp]
    this.update(node, exp, 'text') 
  }

  // k-html
  html (node, exp) {
    // node.innerHTML = this.$vm[exp]
    this.update(node, exp, 'html')
  }
} 

// 作业
// 1.事件的绑定
// 2.v-model的实现